package cn.tedu._07springaop.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;

import java.util.Arrays;

/*@Aspect
1.标识此类为切面类
2.当开发者调用目标方法时,切面类的方法会自动执行
*/
@Component
@Aspect
public class LogAspect {
    /* @Before前置通知
    * */
    //@Before(value = "execution(public int cn.tedu._07springaop.aop.CalculatorImpl.*(..))")
    public void beforeMethod(JoinPoint joinPoint){
        /*JoinPoint参数:连接点对象,被拦截的目标方法
        * 获取目标方法名joinPoint.getSignature().getName()
        * 获取目标方法参数joinPoint.getArgs()*/

        String name = joinPoint.getSignature().getName();
        String args = Arrays.toString(joinPoint.getArgs());
        System.out.println("1.前置通知:"+name+"**方法开始,参数为:"+args);
    }
    /*@AfterReturning 返回通知,目标方法成功结束后执行
    * 权限:获取目标方法的返回值*/
    //@AfterReturning(value = "execution(public int cn.tedu._07springaop.aop.CalculatorImpl.*(..))",returning = "r")
    public void afterReturningMethod(JoinPoint joinPoint,Object r){
        String name = joinPoint.getSignature().getName();
        System.out.println("2.返回通知:"+name+"方法结束,结果为:"+r);
    }
    /*@AfterThrowing 异常通知 ,目标方法抛出异常时执行*/
    //@AfterThrowing(value = "execution(public int cn.tedu._07springaop.aop.CalculatorImpl.*(..))",throwing = "ex")
    public  void afterThrowMethod(JoinPoint joinPoint,Throwable ex){
        String name = joinPoint.getSignature().getName();
        System.out.println("3.异常通知,"+name+"方法抛出异常:"+ex.getMessage());
    }
    /*@After 后置通知 ,目标方法无论成功结束还是异常结束都会执行,无法获取目标方法任何信息*/
    //@After(value = "execution(public int cn.tedu._07springaop.aop.CalculatorImpl.*(..))")
    public void afterMethod(JoinPoint joinPoint){
        System.out.println("4.后置通知,毛线用没有纯看板");
    }
    /*@Around 环绕通知
    * 等价于前置通知+返回通知+异常通知+后置通知;
    * */
    @Around(value = "execution(public int cn.tedu._07springaop.aop.CalculatorImpl.*(..))")
    public Object aroundMethod(ProceedingJoinPoint joinPoint){
        //try...catch...finally包裹目标方法
        Object result = null;
        try{
//           /*1.前置通知
//           2.调用方法
//           3.返回通知*/
            System.out.println("--环绕前置通知--");
            result = joinPoint.proceed();
            System.out.println("--环绕返回通知--");
        } catch (Throwable e) {
            System.out.println("--环绕异常通知--");
            throw new RuntimeException(e);
        }finally {
            System.out.println("--环绕后置通知--");
        }
        return result ;
    }
}
